package penguin.masking;

import penguin.masking.filter.DbsFilter;
import penguin.masking.filter.MaskingFilter;
import penguin.masking.filter.TableFilter;
import penguin.masking.filter.UserFilter;
import penguin.masking.jdbc.DBMetaHandler;
import penguin.masking.jdbc.MetaHandlerFactory;

import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author wuxh
 * @version 1.0.0
 */
public class DataMaskingProcessImpl implements DataMaskingProcess {

    WordManager wordManager;
    List<MaskingFilter> filters;
    MaskingContext context;

    @Override
    public void init(WordManager wordManager) {
        context = MaskingContext.context();
        this.wordManager = wordManager;
        filters = new ArrayList<>();
        filters.add(new UserFilter());
        filters.add(new DbsFilter());
        filters.add(new TableFilter());
    }

    @Override
    public <M> M doMasking(ResultSet set, Object columnName, M v) {
        if (context.isStopped() || context.isUninstall()) {
            return v;
        }
        //do filter start
        if (v == null) {
            return null;
        }
        DBMetaHandler handler = MetaHandlerFactory.getInstance().handler(set);
        int columnIndex = handler.columnIndex(set, columnName);
        if (columnIndex == -1) {
            return v;
        }
        for (MaskingFilter filter : filters) {
            if (filter.doFilter(set, columnName, columnIndex)) {
                return v;
            }
        }

        if (!(v instanceof String)) {
            return v;
        }
        String value = (String) v;
        //如果脱敏了
        if (isMasking(value)) {
            return v;
        }
        //do filter end
        //refresh Words
        if (context.isRefreshEnable()) {
            wordManager.start();
        }
        //column masking
        String name = handler.columnName(set, columnName);
        SensitiveWordMasking masking = MaskingContext.context().isMultiple() ?
                wordManager.matchMasking(handler.userName(set)) : wordManager.getDefaultMasking();
        if (masking.haveColumnMasking()) {
            String tableName = handler.tableName(set, columnIndex);
            boolean columnMasking = masking.columnMasking(tableName, name);
            if (columnMasking) {
                return (M) context.addReduction(value);
            }
        }
        //regex masking
        value = masking.regexMasking(value);
        //key masking
        value = masking.filter(value);
        return (M) value;
    }

    @Override
    public <R> R doReduction(R v) {
        //如果只读、卸载，将不会做数据恢复
        if (context.getRead() || context.isUninstall()) {
            return v;
        }
        //目前支持字符串
        if (v instanceof String) {
            String _value = (String) v;
            Matcher matcher = Pattern.compile(MaskingContext.REPLACEMENT_REGEX).matcher(_value);
            boolean result = matcher.find();
            if (result) {
                StringBuffer sb = new StringBuffer();
                do {
                    String matchString = matcher.group(0);
                    String submatchStr = matcher.group(1);
                    String value = context.cache().value(submatchStr);
                    if (value == null) {
                        throw new RuntimeException(matchString + "未找到要恢复的数据！");
                    }
                    matcher.appendReplacement(sb, value);
                    result = matcher.find();
                } while (result);
                matcher.appendTail(sb);
                return (R) sb.toString();
            }
        }
        return v;
    }

    @Override
    public <R> boolean isMasking(R v) {
        if (v instanceof String) {
            String _v = (String) v;
            Matcher matcher = Pattern.compile(MaskingContext.REPLACEMENT_REGEX).matcher(_v);
            boolean result = matcher.find();
            return result;
        }
        return false;
    }
}
